#include "precompile.h"

#include "Controller.h"
#include "Document.h"
#include "View.h"
#include "command/Command.h"

Controller::Controller()
	:m_activeDocumentControl(NULL)
{
}

Controller::~Controller()
{
	DocumentControls::iterator itbegin = m_documentControls.begin();
	DocumentControls::iterator itend = m_documentControls.end();
	for (; itbegin != itend; ++itbegin)
	{
		DocumentControl* control = *itbegin;
		delete control;
	}
	m_documentControls.clear();
}

void Controller::ActivateControl(IView* view,IDocument* document)
{
	ASSERT(view && document);

	DocumentControls::iterator itfind = FindDocumentControl(document,view);
	if (itfind == m_documentControls.end())
		m_activeDocumentControl = AddDocumentControl(document,view);
	else
		m_activeDocumentControl = *itfind;
}

void Controller::CloseControl(IView* view,IDocument* document)
{
	DocumentControls::iterator itfind = FindDocumentControl(document,view);
	ASSERT(itfind != m_documentControls.end());
	if (itfind != m_documentControls.end())
	{
		DocumentControl* control = *itfind;
		delete control;
		m_documentControls.erase(itfind);
	}
}

Controller::DocumentControls::iterator Controller::FindDocumentControl(IDocument* document,IView* view)
{
	DocumentControls::iterator itbegin = m_documentControls.begin();
	DocumentControls::iterator itend = m_documentControls.end();
	DocumentControls::iterator itfind = itend;
	for (; itbegin != itend; ++itbegin)
	{
		DocumentControl* control = *itbegin;
		if (control->document == document && control->view == view)
		{
			itfind = itbegin;
			break;
		}
	}

	return itfind;
}

Controller::DocumentControl* Controller::AddDocumentControl(IDocument* document,IView* view)
{
	DocumentControl* control = new DocumentControl;
	sys::ObjectPtr commandProcessor;
	commandProcessor.CreateObject(CLSID_CommandProcessor);
	control->commandProcessor = commandProcessor;
	control->document = document;
	control->view = view;

	m_documentControls.push_back(control);
	return control;
}

bool Controller::ExecuteCommand(uint32 commandid,ExecuteArgument* arg/*=NULL*/)
{
	CommandDictionary::iterator itfind = m_commands.find(commandid);
	if (itfind != m_commands.end())
	{
		sys::InterfacePtr<ICommand> pIFCommand(itfind->second);

		if(m_activeDocumentControl)
		{
			sys::InterfacePtr<ICommandProcessor> pIFCommandProcessor(m_activeDocumentControl->commandProcessor);
			View* view = (View*)m_activeDocumentControl->view;
			StateContext* ctx = view->GetStateContext();
			ctx->SetRoot(m_activeDocumentControl->document->GetRoot());

			Command* command = (Command*)pIFCommand.P();
			command->SetStateContext(ctx);
			command->SetArgument(arg);
			pIFCommandProcessor->ExecuteCommand(pIFCommand);


			//update views
			m_activeDocumentControl->document->UpdateAllViews(m_activeDocumentControl->view);
		}
		else
			pIFCommand->Execute();
		return true;
	}
	return false;
}

void Controller::AddCommand(uint32 commandid,vclsid clsidCommand)
{
	sys::ObjectPtr objCommand;
	objCommand.CreateObject(clsidCommand);
	if(objCommand.IsNotNull())
	{
		m_commands[commandid] = objCommand;
	}
}